# This code is heavily based on the implementation in `dbx_build_tools`:
#   Ref: https://github.com/dropbox/dbx_build_tools/blob/master/thirdparty/openssl/BUILD.openssl.tail

load("@openssl-generated-overlay//:collate_into_directory.bzl", "collate_into_directory")
load("@openssl-generated-overlay//:common.bzl", "COMMON_GENERATED_FILES")
load(
    "@openssl-generated-overlay//:constants-darwin64-arm64-cc.bzl",
    _DARWIN_ARM64_GEN_FILES = "GEN_FILES",
    _DARWIN_ARM64_LIBCRYPTO_DEFINES = "LIBCRYPTO_DEFINES",
    _DARWIN_ARM64_LIBCRYPTO_SRCS = "LIBCRYPTO_SRCS",
    _DARWIN_ARM64_LIBSSL_DEFINES = "LIBSSL_DEFINES",
    _DARWIN_ARM64_LIBSSL_SRCS = "LIBSSL_SRCS",
    _DARWIN_ARM64_OPENSSL_APP_DEFINES = "LIBSSL_DEFINES",
    _DARWIN_ARM64_OPENSSL_APP_SRCS = "OPENSSL_APP_SRCS",
    _DARWIN_ARM64_OPENSSL_DEFINES = "OPENSSL_DEFINES",
    _NIX_ARM64_PERLASM_GEN = "PERLASM_GEN",
)
load(
    "@openssl-generated-overlay//:constants-darwin64-x86_64-cc.bzl",
    _DARWIN_X86_64_GEN_FILES = "GEN_FILES",
    _DARWIN_X86_64_LIBCRYPTO_DEFINES = "LIBCRYPTO_DEFINES",
    _DARWIN_X86_64_LIBCRYPTO_SRCS = "LIBCRYPTO_SRCS",
    _DARWIN_X86_64_LIBSSL_DEFINES = "LIBSSL_DEFINES",
    _DARWIN_X86_64_LIBSSL_SRCS = "LIBSSL_SRCS",
    _DARWIN_X86_64_OPENSSL_APP_DEFINES = "LIBSSL_DEFINES",
    _DARWIN_X86_64_OPENSSL_APP_SRCS = "OPENSSL_APP_SRCS",
    _DARWIN_X86_64_OPENSSL_DEFINES = "OPENSSL_DEFINES",
)
load(
    "@openssl-generated-overlay//:constants-linux-aarch64.bzl",
    _LINUX_ARM64_GEN_FILES = "GEN_FILES",
    _LINUX_ARM64_LIBCRYPTO_DEFINES = "LIBCRYPTO_DEFINES",
    _LINUX_ARM64_LIBCRYPTO_SRCS = "LIBCRYPTO_SRCS",
    _LINUX_ARM64_LIBSSL_DEFINES = "LIBSSL_DEFINES",
    _LINUX_ARM64_LIBSSL_SRCS = "LIBSSL_SRCS",
    _LINUX_ARM64_OPENSSL_APP_DEFINES = "LIBSSL_DEFINES",
    _LINUX_ARM64_OPENSSL_APP_SRCS = "OPENSSL_APP_SRCS",
    _LINUX_ARM64_OPENSSL_DEFINES = "OPENSSL_DEFINES",
)
load(
    "@openssl-generated-overlay//:constants-linux-x86_64-clang.bzl",
    _LINUX_X86_64_GEN_FILES = "GEN_FILES",
    _LINUX_X86_64_LIBCRYPTO_DEFINES = "LIBCRYPTO_DEFINES",
    _LINUX_X86_64_LIBCRYPTO_SRCS = "LIBCRYPTO_SRCS",
    _LINUX_X86_64_LIBSSL_DEFINES = "LIBSSL_DEFINES",
    _LINUX_X86_64_LIBSSL_SRCS = "LIBSSL_SRCS",
    _LINUX_X86_64_OPENSSL_APP_DEFINES = "LIBSSL_DEFINES",
    _LINUX_X86_64_OPENSSL_APP_SRCS = "OPENSSL_APP_SRCS",
    _LINUX_X86_64_OPENSSL_DEFINES = "OPENSSL_DEFINES",
    _NIX_X86_64_PERLASM_GEN = "PERLASM_GEN",
)
load(
    "@openssl-generated-overlay//:constants-VC-WIN64-CLANGASM-ARM.bzl",
    _WINDOWS_ARM64_GEN_FILES = "GEN_FILES",
    _WINDOWS_ARM64_LIBCRYPTO_DEFINES = "LIBCRYPTO_DEFINES",
    _WINDOWS_ARM64_LIBCRYPTO_SRCS = "LIBCRYPTO_SRCS",
    _WINDOWS_ARM64_LIBSSL_DEFINES = "LIBSSL_DEFINES",
    _WINDOWS_ARM64_LIBSSL_SRCS = "LIBSSL_SRCS",
    _WINDOWS_ARM64_OPENSSL_APP_DEFINES = "LIBSSL_DEFINES",
    _WINDOWS_ARM64_OPENSSL_APP_SRCS = "OPENSSL_APP_SRCS",
    _WINDOWS_ARM64_OPENSSL_DEFINES = "OPENSSL_DEFINES",
    _WINDOWS_ARM64_PERLASM_GEN = "PERLASM_GEN",
)
load(
    "@openssl-generated-overlay//:constants-VC-WIN64A-masm.bzl",
    _WINDOWS_X86_64_GEN_FILES = "GEN_FILES",
    _WINDOWS_X86_64_LIBCRYPTO_DEFINES = "LIBCRYPTO_DEFINES",
    _WINDOWS_X86_64_LIBCRYPTO_SRCS = "LIBCRYPTO_SRCS",
    _WINDOWS_X86_64_LIBSSL_DEFINES = "LIBSSL_DEFINES",
    _WINDOWS_X86_64_LIBSSL_SRCS = "LIBSSL_SRCS",
    _WINDOWS_X86_64_OPENSSL_APP_DEFINES = "LIBSSL_DEFINES",
    _WINDOWS_X86_64_OPENSSL_APP_SRCS = "OPENSSL_APP_SRCS",
    _WINDOWS_X86_64_OPENSSL_DEFINES = "OPENSSL_DEFINES",
    _WINDOWS_X86_64_PERLASM_GEN = "PERLASM_GEN",
)
load("@openssl-generated-overlay//:perl_genrule.bzl", "perl_genrule")
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
load("//:utils.bzl", "fix_paths_for_windows", "get_repo_name", "parse_perlasm_gen", "remove_dupes")

_REPO_NAME = get_repo_name()

cc_library(
    name = "crypto-textual-hdrs",
    textual_hdrs = [
        "crypto/des/ncbc_enc.c",
    ] + select({
        "@platforms//os:windows": [
            "crypto/LPdir_win32.c",
            "crypto/LPdir_win.c",
            "crypto/LPdir_wince.c",
        ],
        "//conditions:default": ["crypto/LPdir_unix.c"],
    }),
)

COMMON_OPENSSL_APP_SRCS = glob(
    [
        "include/internal/*.h",
        "apps/include/*.h",
        "apps/*.h",
        "include/openssl/*.h",
    ],
    exclude = COMMON_GENERATED_FILES,
) + [
    ":apps/progs.h",
    ":include/openssl/asn1.h",
    ":include/openssl/asn1t.h",
    ":include/openssl/conf.h",
    ":include/openssl/crypto.h",
    ":include/openssl/ct.h",
    ":include/openssl/err.h",
    ":include/openssl/bio.h",
    ":include/openssl/cmp.h",
    ":include/openssl/cms.h",
    ":include/openssl/crmf.h",
    ":include/openssl/configuration.h",
    ":include/openssl/core_names.h",
    ":include/openssl/fipskey.h",
    ":include/openssl/ess.h",
    ":include/openssl/lhash.h",
    ":include/openssl/opensslconf.h",
    ":include/openssl/opensslv.h",
    ":include/openssl/ocsp.h",
    ":include/openssl/pkcs7.h",
    ":include/openssl/pkcs12.h",
    ":include/openssl/safestack.h",
    ":include/openssl/srp.h",
    ":include/openssl/ssl.h",
    ":include/openssl/ui.h",
    ":include/openssl/x509.h",
    ":include/openssl/x509v3.h",
    ":include/openssl/x509_vfy.h",
]

# Some source files are missing from OpenSSL metadata so we never pick them up.
MISSING_OPENSSL_WINDOWS_SRCS = ["apps/lib/win32_init.c"]

ALL_OPENSSL_APP_SRCS = COMMON_OPENSSL_APP_SRCS + select({
    "//configs:darwin_arm64": _DARWIN_ARM64_OPENSSL_APP_SRCS,
    "//configs:darwin_x86_64": _DARWIN_X86_64_OPENSSL_APP_SRCS,
    "//configs:linux_aarch64": _LINUX_ARM64_OPENSSL_APP_SRCS,
    "//configs:linux_x86_64": _LINUX_X86_64_OPENSSL_APP_SRCS,
    "//configs:windows_arm64": fix_paths_for_windows(_WINDOWS_ARM64_OPENSSL_APP_SRCS) + MISSING_OPENSSL_WINDOWS_SRCS,
    "//configs:windows_x64": fix_paths_for_windows(_WINDOWS_X86_64_OPENSSL_APP_SRCS) + MISSING_OPENSSL_WINDOWS_SRCS,
})

OPENSSL_APP_NIX_COPTS = [
    "-iquote",
    "$(BINDIR)/external/{}/apps".format(_REPO_NAME),
    "-iquote",
    "external/{}/apps".format(_REPO_NAME),
    "-iquote",
    "external/{}/apps/include".format(_REPO_NAME),
]

OPENSSL_APP_WINDOWS_COPTS = [
    "/I$(BINDIR)/external/{}/apps".format(_REPO_NAME),
    "/Iexternal/{}/apps".format(_REPO_NAME),
    "/Iexternal/{}/apps/include".format(_REPO_NAME),
]

OPENSSL_APP_NIX_LINKOPTS = [
]

OPENSSL_APP_WINDOWS_LINKOPTS = [
    "-defaultlib:ws2_32.lib",
    "-defaultlib:advapi32.lib",
    "-defaultlib:user32.lib",
    "-defaultlib:crypt32.lib",
]

COMMON_OPENSSL_WINDOWS_DEFINES = [
    "_WINSOCKAPI_",
    "OPENSSL_SYS_WINCE",
    "WIN32_LEAN_AND_MEAN",
]

COMMON_OPENSSL_DEFINES = select({
    "//configs:windows_arm64": COMMON_OPENSSL_WINDOWS_DEFINES,
    "//configs:windows_x64": COMMON_OPENSSL_WINDOWS_DEFINES,
    "//conditions:default": [],
})

COMMON_OPENSSL_COPTS = [
    # If someone wants to link with -fPIC, the objects they're linking need to have been built with it.
    # Add this flag so that people can choose to link that way if they want to.
    "-fPIC",
] + [
    # This hardcoded path into the system mean we will find the system certs. Note Debian sets
    # OPENSSLDIR=/usr/lib/ssl, but /usr/lib/ssl mostly consists of symlinks into /etc/ssl. We
    # must set /etc/ssl here because some environments (e.g., YSS root filesystems) don't have
    # /usr/lib/ssl at all.
    "-DOPENSSLDIR=\\\"/etc/ssl\\\"",
    # This is basically a no-op, since we've disabled dynamic loading of engines.
    '-DENGINESDIR=\\"/usr/lib/engines-3.0\\"',
    # also basically a no-op
    "-DMODULESDIR=\\\"/dev/null\\\"",
    "-DL_ENDIAN",
    "-DOPENSSL_USE_NODELETE",
] + select({
    "//configs:linux_aarch64": ["-mno-outline-atomics"],
    "//conditions:default": [],
}) + select({
    "//configs:windows_arm64": [
        "/Iexternal/{}/include".format(_REPO_NAME),
        "/VERBOSE",
    ],
    "//configs:windows_x64": [
        "/Iexternal/{}/include".format(_REPO_NAME),
        "/VERBOSE",
    ],
    "//conditions:default": [
        # As described in https://github.com/openssl/openssl/issues/4575, OpenSSL doesn't mark its
        # assembly files as not requiring an executable stack. Pass --noexecstack to the assembler
        # to do this.
        "-Wa,--noexecstack",
        "-Wno-unused-command-line-argument",
        "-I",
        "external/{}/include".format(_REPO_NAME),
    ],
})

cc_binary(
    name = "openssl",
    srcs = ALL_OPENSSL_APP_SRCS,
    copts = COMMON_OPENSSL_COPTS + select({
        "//configs:darwin_arm64": _DARWIN_ARM64_OPENSSL_APP_DEFINES,
        "//configs:darwin_x86_64": _DARWIN_X86_64_OPENSSL_APP_DEFINES,
        "//configs:linux_aarch64": _LINUX_ARM64_OPENSSL_APP_DEFINES,
        "//configs:linux_x86_64": _LINUX_X86_64_OPENSSL_APP_DEFINES,
        "//configs:windows_arm64": _WINDOWS_ARM64_OPENSSL_APP_DEFINES,
        "//configs:windows_x64": _WINDOWS_X86_64_OPENSSL_APP_DEFINES,
    }) + select({
        "//configs:windows_arm64": OPENSSL_APP_WINDOWS_COPTS,
        "//configs:windows_x64": OPENSSL_APP_WINDOWS_COPTS,
        "//conditions:default": OPENSSL_APP_NIX_COPTS,
    }),
    defines = COMMON_OPENSSL_DEFINES,
    linkopts = select({
        "//configs:windows_arm64": OPENSSL_APP_WINDOWS_LINKOPTS,
        "//configs:windows_x64": OPENSSL_APP_WINDOWS_LINKOPTS,
        "//conditions:default": OPENSSL_APP_NIX_LINKOPTS,
    }),
    visibility = ["//visibility:public"],
    deps = [":ssl"],
)

NIX_ARM64_PERLASM_TOOLS_AND_OUTS, NIX_ARM64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT = parse_perlasm_gen(_NIX_ARM64_PERLASM_GEN)

NIX_X86_64_PERLASM_TOOLS_AND_OUTS, NIX_X86_64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT = parse_perlasm_gen(_NIX_X86_64_PERLASM_GEN)

WINDOWS_ARM64_PERLASM_TOOLS_AND_OUTS, WINDOWS_ARM64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT = parse_perlasm_gen(_WINDOWS_ARM64_PERLASM_GEN)

WINDOWS_X86_64_PERLASM_TOOLS_AND_OUTS, WINDOWS_X86_64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT = parse_perlasm_gen(_WINDOWS_X86_64_PERLASM_GEN)

PERLASM_TOOLS = glob(
    ["crypto/perlasm/*.pl"],
    exclude = COMMON_GENERATED_FILES,
)

perl_genrule(
    name = "perlasm_genfiles",
    additional_srcs = PERLASM_TOOLS + ["crypto/ec/ecp_nistz256_table.c"],
    assembly_flavor = select({
        "//configs:darwin_arm64": "ios64",
        "//configs:darwin_x86_64": "macosx",
        "//configs:linux_aarch64": "linux64",
        "//configs:linux_x86_64": "elf",
        "//configs:windows_arm64": "win64",
        "//configs:windows_x64": "masm",
    }),
    is_unix = select({
        "@platforms//os:windows": False,
        "//conditions:default": True,
    }),
    srcs_to_outs = select({
        "//configs:darwin_arm64": NIX_ARM64_PERLASM_TOOLS_AND_OUTS,
        "//configs:darwin_x86_64": NIX_X86_64_PERLASM_TOOLS_AND_OUTS,
        "//configs:linux_aarch64": NIX_ARM64_PERLASM_TOOLS_AND_OUTS,
        "//configs:linux_x86_64": NIX_X86_64_PERLASM_TOOLS_AND_OUTS,
        "//configs:windows_arm64": WINDOWS_ARM64_PERLASM_TOOLS_AND_OUTS,
        "//configs:windows_x64": WINDOWS_X86_64_PERLASM_TOOLS_AND_OUTS,
    }),
    srcs_to_outs_dupes = select({
        "//configs:darwin_arm64": NIX_ARM64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT,
        "//configs:darwin_x86_64": NIX_X86_64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT,
        "//configs:linux_aarch64": NIX_ARM64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT,
        "//configs:linux_x86_64": NIX_X86_64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT,
        "//configs:windows_arm64": WINDOWS_ARM64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT,
        "//configs:windows_x64": WINDOWS_X86_64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT,
    }),
)

COMMON_LIBCRYPTO_SRCS = glob(
    [
        "crypto/**/*.h",
        "crypto/*.h",
        "include/crypto/**/*.h",
        "include/internal/*.h",
        "include/openssl/*.h",
        "providers/**/*.h",
        "providers/*.inc",
        "providers/implementations/**/*.inc",
    ],
    exclude = COMMON_GENERATED_FILES,
)

# We miss some sources and headers when doing the normal extraction
OTHER_LIBCRYPTO_WINDOWS_SRCS = [
    "ms/uplink.h",
    "ms/applink.c",
    "engines/e_capi_err.h",
    "engines/e_capi_err.c",
]

ALL_LIBCRYPTO_SRCS = COMMON_LIBCRYPTO_SRCS + select({
    "//configs:darwin_arm64": remove_dupes(
        _DARWIN_ARM64_LIBCRYPTO_SRCS,
        NIX_ARM64_PERLASM_TOOLS_AND_OUTS.values() + NIX_ARM64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT.values(),
    ),
    "//configs:darwin_x86_64": remove_dupes(
        _DARWIN_X86_64_LIBCRYPTO_SRCS,
        NIX_X86_64_PERLASM_TOOLS_AND_OUTS.values() + NIX_X86_64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT.values(),
    ),
    "//configs:linux_aarch64": remove_dupes(
        _LINUX_ARM64_LIBCRYPTO_SRCS,
        NIX_ARM64_PERLASM_TOOLS_AND_OUTS.values() + NIX_ARM64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT.values(),
    ),
    "//configs:linux_x86_64": remove_dupes(
        _LINUX_X86_64_LIBCRYPTO_SRCS,
        NIX_X86_64_PERLASM_TOOLS_AND_OUTS.values() + NIX_X86_64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT.values(),
    ),
    "//configs:windows_arm64": remove_dupes(
        fix_paths_for_windows(_WINDOWS_ARM64_LIBCRYPTO_SRCS),
        WINDOWS_ARM64_PERLASM_TOOLS_AND_OUTS.values() + WINDOWS_ARM64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT.values(),
    ) + OTHER_LIBCRYPTO_WINDOWS_SRCS,
    "//configs:windows_x64": remove_dupes(
        fix_paths_for_windows(_WINDOWS_X86_64_LIBCRYPTO_SRCS),
        WINDOWS_X86_64_PERLASM_TOOLS_AND_OUTS.values() + WINDOWS_X86_64_PERLASM_TOOLS_AND_OUTS_DUPES_DICT.values(),
    ) + OTHER_LIBCRYPTO_WINDOWS_SRCS,
})

EXISTING_LIBCRYPTO_HDRS = glob(
    [
        "include/openssl/*.h",
        "include/openssl/**/*.h",
        "include/crypto/*.h",
        "include/crypto/**/*.h",
    ],
)

LIBCRYPTO_NIX_COPTS = [
    "-iquote",
    "external/{}/providers/implementations/macs".format(_REPO_NAME),
    "-iquote",
    "external/{}/providers/implementations/include".format(_REPO_NAME),
    "-iquote",
    "external/{}/providers/common/include".format(_REPO_NAME),
    "-iquote",
    "$(BINDIR)/external/{}/providers/common/include".format(_REPO_NAME),
    "-iquote",
    "$(BINDIR)/external/{}/crypto".format(_REPO_NAME),
    "-iquote",
    "external/{}/crypto".format(_REPO_NAME),
    "-I",
    "external/{}/providers/implementations/include".format(_REPO_NAME),
]

LIBCRYPTO_WINDOWS_COPTS = [
    "/Iexternal/{}/providers/implementations/macs".format(_REPO_NAME),
    "/Iexternal/{}/providers/implementations/include".format(_REPO_NAME),
    "/Iexternal/{}/providers/common/include".format(_REPO_NAME),
    "/I$(BINDIR)/external/{}/providers/common/include".format(_REPO_NAME),
    "/I$(BINDIR)/external/{}/crypto".format(_REPO_NAME),
    "/Iexternal/{}/crypto".format(_REPO_NAME),
    "/Iexternal/{}/providers/implementations/include".format(_REPO_NAME),
]

ALL_LIBCRYPTO_HDRS = EXISTING_LIBCRYPTO_HDRS + [":generated-headers"]

# Windows needs some additional include directories.
LIBCRYPTO_WINDOWS_INCLUDES = [
    "ms",
    "engines",
    "crypto/bn",
    "crypto",
]

cc_library(
    name = "crypto",
    # Some of the srcs are duplicated because we have to glob over the directories with missing files
    # as only some of them are picked up.
    srcs = ALL_LIBCRYPTO_SRCS + [":perlasm_genfiles"],
    hdrs = ALL_LIBCRYPTO_HDRS,
    additional_compiler_inputs = [
        ":generated-headers",
    ] + glob(
        # There are some .c files that are conditionally included textually, we want them to be
        # available
        ["providers/implementations/**/*.c"],
        exclude = COMMON_GENERATED_FILES,
    ),
    # To make sure downstream targets add the right copts to be able to include the headers.
    copts = COMMON_OPENSSL_COPTS + select({
        "//configs:darwin_arm64": _DARWIN_ARM64_OPENSSL_DEFINES,
        "//configs:darwin_x86_64": _DARWIN_X86_64_OPENSSL_DEFINES,
        "//configs:linux_aarch64": _LINUX_ARM64_OPENSSL_DEFINES,
        "//configs:linux_x86_64": _LINUX_X86_64_OPENSSL_DEFINES,
        "//configs:windows_arm64": _WINDOWS_ARM64_OPENSSL_DEFINES,
        "//configs:windows_x64": _WINDOWS_X86_64_OPENSSL_DEFINES,
    }) + select({
        "//configs:darwin_arm64": _DARWIN_ARM64_LIBCRYPTO_DEFINES,
        "//configs:darwin_x86_64": _DARWIN_X86_64_LIBCRYPTO_DEFINES,
        "//configs:linux_aarch64": _LINUX_ARM64_LIBCRYPTO_DEFINES,
        "//configs:linux_x86_64": _LINUX_X86_64_LIBCRYPTO_DEFINES,
        "//configs:windows_arm64": _WINDOWS_ARM64_LIBCRYPTO_DEFINES,
        "//configs:windows_x64": _WINDOWS_X86_64_LIBCRYPTO_DEFINES,
    }) + select({
        "//configs:windows_arm64": LIBCRYPTO_WINDOWS_COPTS,
        "//configs:windows_x64": LIBCRYPTO_WINDOWS_COPTS,
        "//conditions:default": LIBCRYPTO_NIX_COPTS,
    }),
    defines = COMMON_OPENSSL_DEFINES,
    includes = [
        "include",
    ] + select({
        "//configs:windows_arm64": LIBCRYPTO_WINDOWS_INCLUDES,
        "//configs:windows_x64": LIBCRYPTO_WINDOWS_INCLUDES,
        "//conditions:default": [],
    }),
    linkopts = [
        "-lc",
        "-pthread",
    ],
    visibility = ["//visibility:public"],
    deps = [
        ":crypto-textual-hdrs",
    ],
)

COMMON_LIBSSL_SRCS = glob(
    ["ssl/**/*.h"],
    exclude = COMMON_GENERATED_FILES,
)

ALL_LIBSSL_SRCS = COMMON_LIBSSL_SRCS + select({
    "//configs:darwin_arm64": _DARWIN_ARM64_LIBSSL_SRCS,
    "//configs:darwin_x86_64": _DARWIN_X86_64_LIBSSL_SRCS,
    "//configs:linux_aarch64": _LINUX_ARM64_LIBSSL_SRCS,
    "//configs:linux_x86_64": _LINUX_X86_64_LIBSSL_SRCS,
    "//configs:windows_arm64": fix_paths_for_windows(_WINDOWS_ARM64_LIBSSL_SRCS),
    "//configs:windows_x64": fix_paths_for_windows(_WINDOWS_X86_64_LIBSSL_SRCS),
})

EXISTING_LIBSSL_HDRS = glob(
    ["include/openssl/*.h"],
)

ALL_LIBSSL_HDRS = EXISTING_LIBSSL_HDRS + [":generated-headers"]

cc_library(
    name = "ssl",
    srcs = ALL_LIBSSL_SRCS,
    hdrs = ALL_LIBSSL_HDRS,
    additional_compiler_inputs = [":generated-files"],
    copts = COMMON_OPENSSL_COPTS + select({
        "//configs:darwin_arm64": _DARWIN_ARM64_OPENSSL_DEFINES,
        "//configs:darwin_x86_64": _DARWIN_X86_64_OPENSSL_DEFINES,
        "//configs:linux_aarch64": _LINUX_ARM64_OPENSSL_DEFINES,
        "//configs:linux_x86_64": _LINUX_X86_64_OPENSSL_DEFINES,
        "//configs:windows_arm64": _WINDOWS_ARM64_OPENSSL_DEFINES,
        "//configs:windows_x64": _WINDOWS_X86_64_OPENSSL_DEFINES,
    }) + select({
        "//configs:darwin_arm64": _DARWIN_ARM64_LIBSSL_DEFINES,
        "//configs:darwin_x86_64": _DARWIN_X86_64_LIBSSL_DEFINES,
        "//configs:linux_aarch64": _LINUX_ARM64_LIBSSL_DEFINES,
        "//configs:linux_x86_64": _LINUX_X86_64_LIBSSL_DEFINES,
        "//configs:windows_arm64": _WINDOWS_ARM64_LIBSSL_DEFINES,
        "//configs:windows_x64": _WINDOWS_X86_64_LIBSSL_DEFINES,
    }),
    defines = COMMON_OPENSSL_DEFINES,
    # To make sure downstream targets add the right copts to be able to include the headers.
    includes = ["include"],
    linkopts = ["-lc"],
    visibility = ["//visibility:public"],
    deps = [
        ":crypto",
    ],
)

filegroup(
    name = "generated-files",
    srcs = COMMON_GENERATED_FILES + [":generate-platform-specific-files"],
)

filegroup(
    name = "generated-headers",
    srcs = [f for f in COMMON_GENERATED_FILES + _DARWIN_ARM64_GEN_FILES.keys() if f.endswith(".h")],
)

[
    genrule(
        name = "copy_generated_{}".format(src),
        srcs = ["@openssl-generated-overlay//:{}".format(src)],
        outs = [src],
        cmd = "cp $< $@",
    )
    for src in COMMON_GENERATED_FILES
]

GEN_FILE_CMD = """
cat << 'E_O_F' >$(location {filename})
{contents}
E_O_F
"""

genrule(
    name = "generate-platform-specific-files",
    outs = sorted(_DARWIN_ARM64_GEN_FILES.keys()),
    cmd = select({
        "//configs:darwin_arm64": "\n".join([GEN_FILE_CMD.format(
            contents = v,
            filename = k,
        ) for k, v in _DARWIN_ARM64_GEN_FILES.items()]),
        "//configs:darwin_x86_64": "\n".join([GEN_FILE_CMD.format(
            contents = v,
            filename = k,
        ) for k, v in _DARWIN_X86_64_GEN_FILES.items()]),
        "//configs:linux_aarch64": "\n".join([GEN_FILE_CMD.format(
            contents = v,
            filename = k,
        ) for k, v in _LINUX_ARM64_GEN_FILES.items()]),
        "//configs:linux_x86_64": "\n".join([GEN_FILE_CMD.format(
            contents = v,
            filename = k,
        ) for k, v in _LINUX_X86_64_GEN_FILES.items()]),
        "//configs:windows_arm64": "\n".join([GEN_FILE_CMD.format(
            contents = v,
            filename = k,
        ) for k, v in _WINDOWS_ARM64_GEN_FILES.items()]),
        "//configs:windows_x64": "\n".join([GEN_FILE_CMD.format(
            contents = v,
            filename = k,
        ) for k, v in _WINDOWS_X86_64_GEN_FILES.items()]),
    }),
)

collate_into_directory(
    name = "gen_dir",
    outs_prefix_map = {
        ":crypto": "lib/",
        ":openssl": "bin/",
        ":ssl": "lib/",
    },
    srcs_prefix_map = {
        ":crypto": "external/{}".format(_REPO_NAME),
        ":generated-headers": "external/{}".format(_REPO_NAME),
        ":openssl": "external/{}".format(_REPO_NAME),
        ":ssl": "external/{}".format(_REPO_NAME),
    } | {
        k: "external/{}".format(_REPO_NAME)
        for k in glob(["include/openssl/*.h"])
    },
    visibility = ["//visibility:public"],
)
